package agent_logic

import (
	"context"
	"errors"
	"fmt"
	"net"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"
	"yunzhan/common/models"
	"yunzhan/common/utils"
	agent "yunzhan/rpc-server/pb"

	"yunzhan/api-server/internal/svc"
	"yunzhan/api-server/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type DeployAgentLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// NewDeployAgentLogic 部署agent
func NewDeployAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeployAgentLogic {
	return &DeployAgentLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *DeployAgentLogic) DeployAgent(req *types.DeployAgentRequest) (resp *types.DeployResponse, err error) {
	if req.Nodes == nil || len(req.Nodes) == 0 {
		return &types.DeployResponse{
			Code:    500,
			Message: "未配置节点信息, 无法执行Agent部署",
		}, errors.New("未配置节点信息, 无法执行Agent部署")
	}

	// 启动部署任务
	go l.startDeployment(req)

	return &types.DeployResponse{
		Code:    200,
		Message: "Agent服务部署已开始...",
	}, nil
}

func (l *DeployAgentLogic) startDeployment(req *types.DeployAgentRequest) {

	var wg sync.WaitGroup

	// 创建 LogManager 实例
	logManager := models.NewLogManager(100, fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port))
	defer logManager.Close()

	flushInterval := 5 * time.Second // 刷新间隔
	maxBatchSize := 100              // 最大批量大小
	retryDelay := 2 * time.Second    // 重试延迟
	maxRetries := 3                  // 最大重试次数
	// 创建 ComponentInfoManager 实例
	componentInfoManager := models.NewComponentInfoManager(1000,
		fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port),
		flushInterval,
		maxBatchSize,
		retryDelay,
		maxRetries)
	defer componentInfoManager.Close()

	packageDirectory := req.ConfigInfo.PackagePath
	rtrimDir := utils.Rtrim(packageDirectory, "/")
	agentVersion := req.ConfigInfo.ComponentName
	path := req.ConfigInfo.InstallPath
	installPath := utils.Rtrim(path, "/")

	// 读取并行度配置
	parallelism := l.svcCtx.Config.Parallelism
	if (parallelism <= 0) || (parallelism > len(req.Nodes)) {
		parallelism = len(req.Nodes)
	}
	sem := make(chan struct{}, parallelism)
	for _, node := range req.Nodes {
		wg.Add(1)
		sem <- struct{}{}

		go func(n *agent.NodeInfo) {
			defer func() {
				<-sem
				wg.Done()
			}()

			step := 1
			baseInfo := fmt.Sprintf("包目录: %s, Agent版本: %s, 安装路径: %s", rtrimDir, agentVersion, installPath)

			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", baseInfo, "Agent", "Server")

			// 测试服务是否可达，节点之间通信是否正常
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "测试服务可达性...", "Agent", "Server")
			if err := testNodeConnectivity(n.Host, n.Port); err != nil {
				message := fmt.Sprintf("节点 %s 不可达: %v, 此节点无法部署Agent服务", n.Host, err)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "节点可达性测试通过", "Agent", "Server")
			step++

			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", fmt.Sprintf("开始部署节点 %s...", n.Host), "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建 ssh 连接池...", "Agent", "Server")

			step++
			pool := utils.NewSSHConnectionPool(n.Host, n.Port, n.Username, n.Password, 10)
			client, clientErr := pool.GetConnection()
			if clientErr != nil {
				message := fmt.Sprintf("创建 ssh 连接池异常: %v", clientErr)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer pool.ReleaseConnection(client)

			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建 ssh 连接池完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建 ssh session...", "Agent", "Server")
			step++
			session, sessionErr := client.NewSession()
			if sessionErr != nil {
				message := fmt.Sprintf("创建 ssh session 异常: %v", sessionErr)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer session.Close()

			homeDir := fmt.Sprintf("/home/%s", n.Username)
			if n.Username == "root" {
				homeDir = "/root"
			}
			// 检测家目录是否存在
			checkPathCommand := fmt.Sprintf(`
if [ ! -d "%s" ]; then
   sudo mkdir -p "%s"
fi
sudo chown -R %s:%s %s`, homeDir, homeDir, n.Username, n.Username, homeDir)
			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "执行home目录检查...", "Agent", "Server")
			step++
			checkPathResult, checkPathErr := session.CombinedOutput(checkPathCommand)
			if checkPathErr != nil {
				message := fmt.Sprintf("执行家目录检查异常: %v, output: %s", checkPathErr, checkPathResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "执行家目录检查完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "目录权限修改(750)...", "Agent", "Server")
			step++
			chmodDir, chmodErr := utils.ExecCommand(fmt.Sprintf("sudo chmod -R 750 %s", rtrimDir+"/"+req.ConfigInfo.ComponentName))
			if chmodErr != nil {
				message := fmt.Sprintf("目录权限修改(750)异常: %v, output: %s", chmodErr, chmodDir)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}

			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "目录权限修改(750)完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "分发Agent安装包...", "Agent", "Server")
			scpCommand := fmt.Sprintf(`sshpass -p '%s' scp -o StrictHostKeyChecking=no -r %s %s@%s:%s/`, n.Password, rtrimDir+"/"+req.ConfigInfo.ComponentName, n.Username, n.Host, homeDir)
			if l.svcCtx.Config.EnableRsync {
				scpCommand = fmt.Sprintf(`sshpass -p '%s' rsync -avz -e "ssh -o StrictHostKeyChecking=no" %s %s@%s:%s/`, n.Password, rtrimDir+"/"+req.ConfigInfo.ComponentName, n.Username, n.Host, homeDir)
			}
			step++
			scpResult, scpErr := utils.ExecCommand(scpCommand)
			if scpErr != nil {
				message := fmt.Sprintf("分发Agent安装包异常: %v, output: %s", scpErr, scpResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "分发Agent安装包完成", "Agent", "Server")
			step++
			sessionChown, sessionChownErr := client.NewSession()
			if sessionChownErr != nil {
				message := fmt.Sprintf("创建 chown session 失败: %v", sessionChownErr)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer sessionChown.Close()

			agentHome := installPath + "/" + agentVersion

			mvPathCommand := fmt.Sprintf(`
if [ ! -d "%s" ]; then
   sudo mkdir -p "%s"
fi
sudo mv %s/%s %s/
sudo chown -R %s:%s %s`, installPath, installPath, homeDir, agentVersion, installPath, n.Username, n.Username, agentHome)

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "移动组件目录并修改组件所属用户组", "Agent", "Server")
			step++
			chownResult, chownErr := sessionChown.CombinedOutput(mvPathCommand)
			if chownErr != nil {
				message := fmt.Sprintf("移动组件目录并修改组件所属用户组异常: %v, output: %s", chownErr, chownResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "移动组件目录并修改组件所属用户组完成", "Agent", "Server")

			serviceFile := fmt.Sprintf(`[Unit]
Description=Agent Go Program Service
Documentation=https://example.com/docs
After=network.target

[Service]
User=%s
Group=%s
Type=simple
WorkingDirectory=%s
ExecStart=%s/bin/agent-server -f %s/etc/config.yaml
MemoryMax=%s
LimitNOFILE=65536
LimitNPROC=65536
LimitCORE=infinity
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user_logic.target`, n.Username, n.Username, agentHome, agentHome, agentHome, l.svcCtx.Config.AgentConf.MemoryMax)
			step++
			sessionService, sessionServiceErr := client.NewSession()
			if sessionServiceErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", sessionServiceErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer sessionService.Close()

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建agent-server.service文件...", "Agent", "Server")
			step++
			serviceCommand := fmt.Sprintf("echo '%s' | sudo tee /etc/systemd/system/agent-server.service", serviceFile)
			vimResult, vimErr := sessionService.CombinedOutput(serviceCommand)
			if vimErr != nil {
				message := fmt.Sprintf("创建agent-server.service文件异常: %v, output: %s", vimErr, vimResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建agent-server.service文件完成", "Agent", "Server")

			sessionStart, sessionStartErr := client.NewSession()
			if sessionStartErr != nil {
				message := fmt.Sprintf("创建 start agent session 失败: %v, 节点: %s", sessionStartErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer sessionStart.Close()

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "启动Agent服务...", "Agent", "Server")
			step++
			startCommand := "sudo systemctl daemon-reload && sudo systemctl enable agent-server.service --now"
			startResult, startErr := sessionStart.CombinedOutput(startCommand)
			if startErr != nil {
				message := fmt.Sprintf("启动Agent服务异常: %v, output: %s", startErr, startResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "启动Agent服务完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "等待Agent服务完全启动...", "Agent", "Server")

			checkServiceSession, checkServiceErr := client.NewSession()
			if checkServiceErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", checkServiceErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer checkServiceSession.Close()

			time.Sleep(5 * time.Second)
			step++
			statusCommand := "sudo systemctl is-active agent-server.service"
			checkServiceResult, checkServiceErr := checkServiceSession.CombinedOutput(statusCommand)
			if checkServiceErr != nil || strings.TrimSpace(string(checkServiceResult)) != "active" {
				message := fmt.Sprintf("Agent启动后未正常运行: %v, output: %s", checkServiceErr, checkServiceResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "Agent部署成功", "Agent", "Server")
			step++
			createIDSession, clientErr := client.NewSession()
			if clientErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", clientErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			step++
			createID := fmt.Sprintf("echo %s > %s/tmp/CLUSTER", req.ClusterID, agentHome)
			combinedOutput, createIDErr := createIDSession.CombinedOutput(createID)
			if createIDErr != nil {
				message := fmt.Sprintf("构建CLUSTER文件异常: %v, output: %s", createIDErr, combinedOutput)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "部署node_exporter服务...", "Agent", "Server")

			tarSession, tarSessionErr := client.NewSession()
			if tarSessionErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", tarSessionErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer tarSession.Close()
			step++
			tarCommand := fmt.Sprintf("sudo tar -xzf %s/package/node_exporter-1.8.2.linux-amd64.tar.gz -C %s", agentHome, installPath)
			tarResult, tarErr := tarSession.CombinedOutput(tarCommand)
			if tarErr != nil {
				message := fmt.Sprintf("解压node_exporter安装包异常: %v, output: %s", tarErr, tarResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}

			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "解压node_exporter安装包完成", "Agent", "Server")

			serviceFile = fmt.Sprintf(`[Unit]
Description=linux monitor
Documentation=https://github.com/prometheus_logic/node_exporter
After=network.target

[Service]
User=%s
Group=%s
Type=simple
ExecStart=%s/node_exporter --web.listen-address=:19100
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user_logic.target
`, n.Username, n.Username, installPath+"/node_exporter-1.8.2.linux-amd64")
			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建node-exporter.service文件...", "Agent", "Server")

			step++
			exporterSession, exporterSessionErr := client.NewSession()
			if exporterSessionErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", exporterSessionErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer exporterSession.Close()

			step++
			exporterServiceCommand := fmt.Sprintf("echo '%s' | sudo tee /etc/systemd/system/node-exporter.service", serviceFile)
			exporterResult, exporterErr := exporterSession.CombinedOutput(exporterServiceCommand)
			if exporterErr != nil {
				message := fmt.Sprintf("创建 node-exporter.service 文件异常: %v, output: %s", exporterErr, exporterResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "创建node-exporter.service文件完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "启动node_exporter服务...", "Agent", "Server")

			step++
			exporterStartSession, exporterStartErr := client.NewSession()
			if exporterStartErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, output: %s", exporterErr, exporterResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer exporterStartSession.Close()
			step++
			exporterStartCommand := "sudo systemctl daemon-reload && sudo sudo systemctl enable node-exporter --now"
			exporterStartResult, exporterStartErr := exporterStartSession.CombinedOutput(exporterStartCommand)
			if exporterStartErr != nil {
				message := fmt.Sprintf("启动node_exporter服务异常: %v, output: %s", exporterStartErr, exporterStartResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "启动node_exporter服务完成", "Agent", "Server")

			step++
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "等待node_exporter服务完全启动...", "Agent", "Server")

			time.Sleep(3 * time.Second)
			step++
			nodeExporterSession, nodeExporterErr := client.NewSession()
			if nodeExporterErr != nil {
				message := fmt.Sprintf("创建 ssh session 失败: %v, 节点: %s", nodeExporterErr, n.Host)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			defer nodeExporterSession.Close()
			step++
			statusCommand = "sudo systemctl is-active node-exporter.service"
			nodeExporterServiceResult, nodeExporterServiceErr := nodeExporterSession.CombinedOutput(statusCommand)
			if nodeExporterServiceErr != nil || strings.TrimSpace(string(nodeExporterServiceResult)) != "active" {
				message := fmt.Sprintf("node_exporter服务启动后未正常运行: %v, output: %s", nodeExporterServiceErr, nodeExporterServiceResult)
				logManager.SendLog(req.ClusterID, n.Host, step, "ERROR", message, "Agent", "Server")
				return
			}
			logManager.SendLog(req.ClusterID, n.Host, step, "INFO", "node_exporter服务部署成功", "Agent", "Server")

			exporterInfo := &models.ComponentInfo{
				ClusterID:      req.ClusterID,
				ComponentName:  "node_exporter",
				Version:        "1.8.2",
				NodeHost:       n.Host,
				NodeIP:         n.Host,
				ComponentRole:  "Server",
				HomePath:       installPath + "/node_exporter-1.8.2.linux-amd64",
				DataStorageDir: "",
				Port:           "19100",
				Status:         true,
				AdditionalInfo: "",
			}

			componentInfoManager.SendComponentInfo(exporterInfo)
		}(node)
	}
	wg.Wait()
}

// testNodeConnectivity 测试节点的可达性
func testNodeConnectivity(host string, port string) error {
	address := fmt.Sprintf("%s:%s", host, port)

	var pingCmd *exec.Cmd
	if runtime.GOOS == "windows" {
		pingCmd = exec.Command("ping", "-n", "3", host)
	} else {
		pingCmd = exec.Command("ping", "-c", "3", host)
	}

	if err := pingCmd.Run(); err != nil {
		return fmt.Errorf("ping 节点 %s 失败: %v", host, err)
	}

	conn, err := net.DialTimeout("tcp", address, 5*time.Second)
	if err != nil {
		return fmt.Errorf("连接到 %s 失败: %v", address, err)
	}
	conn.Close()

	return nil
}
